package com.ochnas.volunteersignup.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.springframework.orm.jpa.support.JpaDaoSupport;

import com.ochnas.volunteersignup.domain.Event;
import com.ochnas.volunteersignup.domain.FilledVolunteerRequisition;
import com.ochnas.volunteersignup.domain.Position;
import com.ochnas.volunteersignup.domain.Time;
import com.ochnas.volunteersignup.domain.TimeSlot;
import com.ochnas.volunteersignup.domain.User;

public class VolunteerServiceImpl extends JpaDaoSupport implements
		VolunteerService {
	private Comparator<TimeSlot> comparator = new Comparator<TimeSlot>() {

		@Override
		public int compare(TimeSlot t1, TimeSlot t2) {
			Time t1StartTime = t1.getStartTime();
			Time t2StartTimie = t2.getStartTime();
			if (t1StartTime.getHourOfDay() > t2StartTimie.getHourOfDay()) {
				return 1;
			} else if (t1StartTime.getHourOfDay() < t2StartTimie.getHourOfDay()) {
				return -1;
			} else {
				if (t1StartTime.getMinutes() > t2StartTimie.getMinutes()) {
					return 1;
				} else if (t1StartTime.getMinutes() < t2StartTimie.getMinutes()) {
					return -1;
				}
			}
			return 1;
		}
		
	};
	
	@Override
	public List<Position> findAllFilledPositionsByEvent(Long eventId) {
		Event storedEvent = getJpaTemplate().find(Event.class, eventId);
		String queryString = "select f from FilledVolunteerRequisition f where f.event = ?1";
		List resultList = getJpaTemplate().find(queryString, storedEvent);
		List<Position> positions = new ArrayList<Position>();
		for (Object o: resultList) {
			Position p = getJpaTemplate().find(Position.class, ((FilledVolunteerRequisition)o).getPosition().getId());
			if (p != null) {
				positions.add(p);
			}
		}
		return positions;
	}

	@Override
	public List<TimeSlot> findAllFilledTimeSlotsByEvent(Long eventId) {
		Event storedEvent = getJpaTemplate().find(Event.class, eventId);
		String queryString = "select f from FilledVolunteerRequisition f where f.event = ?1 AND f.timeSlot IS NOT NULL";
		List resultList = getJpaTemplate().find(queryString, storedEvent);
		List<TimeSlot> timeSlots = new ArrayList<TimeSlot>();
		for (Object o: resultList) {
			TimeSlot t = getJpaTemplate().find(TimeSlot.class, ((FilledVolunteerRequisition)o).getTimeSlot().getId());
			if (t != null) {
				timeSlots.add(t);
			}
		}
		return timeSlots;
	}

	@Override
	public List<Event> findAllFutureEvents(Date startDate) {
		String queryString = "select e from Event e where e.startDate > ?1";
		List resultList = getJpaTemplate().find(queryString, startDate);
		return resultList;
	}

	@Override
	public List<Position> findAllOpenPositionsByEvent(Long eventId) {
		Event storedEvent = getJpaTemplate().find(Event.class, eventId);
		List eventPositions = getJpaTemplate().find("select p from Position p where p.event = ?1", storedEvent);
		List<Position> openPositions = new ArrayList<Position>();
		for (Object p: eventPositions) {
			Position position = getJpaTemplate().find(Position.class, ((Position)p).getId());
			int numOfRequiredVolunteersForPosition = position.getRequiredNumberOfVolunteers();
			List timeSlotResults = getJpaTemplate().find("select t from TimeSlot t where t.position = ?1", position);
			if (timeSlotResults.size() > 0) { // position with time slots
				for (Object o: timeSlotResults) {
					int numOfRequiredVolunteersForTimeSlot = ((TimeSlot) o).getQuantityOfVolunteers();
					List resultFilledTimeSlots = getJpaTemplate().
						find("select f from FilledVolunteerRequisition f where f.timeSlot = ?1", o);
					if (resultFilledTimeSlots.size() < numOfRequiredVolunteersForTimeSlot) {
						openPositions.add(position);
					}
				}
			} else { // position without time slots	
				List resultList = getJpaTemplate().find("select f from FilledVolunteerRequisition f where f.position = ?1", position);
				if (resultList.size() < numOfRequiredVolunteersForPosition) {
					openPositions.add(position);
				}
			}
		}
		
		return openPositions;
	}

	@Override
	public List<TimeSlot> findAllOpenTimeSlotsByEvent(Long eventId) {
		Event storedEvent = getJpaTemplate().find(Event.class, eventId);
		List eventPositions = getJpaTemplate().find("select p from Position p where p.event = ?1", storedEvent);
		List<TimeSlot> openTimeSlots = new ArrayList<TimeSlot>();
		for (Object p: eventPositions) {
			Position position = getJpaTemplate().find(Position.class, ((Position)p).getId());
			List timeSlotResults = getJpaTemplate().find("select t from TimeSlot t where t.position = ?1", position);
			if (timeSlotResults.size() > 0) { // position with time slots
				for (Object o: timeSlotResults) {
					TimeSlot timeSlot = getJpaTemplate().find(TimeSlot.class, ((TimeSlot)o).getId());
					int numOfRequiredVolunteersForTimeSlot = ((TimeSlot) o).getQuantityOfVolunteers();
					List resultFilledTimeSlots = getJpaTemplate().
						find("select f from FilledVolunteerRequisition f where f.timeSlot = ?1", o);
					if (resultFilledTimeSlots.size() < numOfRequiredVolunteersForTimeSlot) {
						openTimeSlots.add(timeSlot);
					}
				}
			} 
		}
		
		return openTimeSlots;
	}

	@Override
	public List<Position> findAllPositionsByEvent(Long eventId) {
		Event storedEvent = getJpaTemplate().find(Event.class, eventId);
		List positions = getJpaTemplate().find("select p from Position p where p.event =?", storedEvent);
		return positions;
	}

	@Override
	public String findDetailedVolunteerInfoByEvent(Long eventId) {
		StringBuffer strBuff = new StringBuffer("Detailed Volunteer Information For Event");
		Event storedEvent = getJpaTemplate().find(Event.class, eventId);
		// 2nd line
		strBuff.append("\nEvent: ");
		strBuff.append(storedEvent.getName());
		// 3rd line
		strBuff.append("\nDate: ");
		strBuff.append(storedEvent.getStartDate());
		strBuff.append(" to ");
		strBuff.append(storedEvent.getEndDate());
		// 4th line
		strBuff.append("\nTime ");
		strBuff.append(storedEvent.getStartTime());
		strBuff.append(" to ");
		strBuff.append(storedEvent.getEndTime());
		List eventPositions = getJpaTemplate().find("select p from Position p where p.event = ?1", storedEvent);
		for (Object p: eventPositions) {
			Position position = getJpaTemplate().find(Position.class, ((Position)p).getId());
			List resultList = getJpaTemplate().find("select f from FilledVolunteerRequisition f where f.position = ?1", position);
			if (!resultList.isEmpty()) {
				strBuff.append("\nPosition: ");
				strBuff.append(position.getName());
			}
			List timeSlotResults = getJpaTemplate().find("select t from TimeSlot t where t.position = ?1", position);
			
			if (timeSlotResults.size() > 0) { // position with time slots
				Collections.sort(timeSlotResults, comparator);
				for (Object o: timeSlotResults) {
					List resultFilledTimeSlots = getJpaTemplate().
						find("select f from FilledVolunteerRequisition f where f.timeSlot = ?1", o);
					if (!resultFilledTimeSlots.isEmpty()) {
						TimeSlot timeSlot = (TimeSlot) o;
						strBuff.append("\n\t");
						strBuff.append(timeSlot.getStartTime().toString());
						strBuff.append(" to ");
						strBuff.append(timeSlot.getEndTime().toString());
					}
					for (Object ft: resultFilledTimeSlots) {
						FilledVolunteerRequisition filledReq = getJpaTemplate().find(FilledVolunteerRequisition.class, 
								((FilledVolunteerRequisition)ft).getId());
						User fpUser = getJpaTemplate().find(User.class, filledReq.getUser().getId());
						strBuff.append("\n\t\t");
						strBuff.append(fpUser.getFirstName());
						strBuff.append(" ");
						strBuff.append(fpUser.getLastName());
						strBuff.append("\n\t\t\tEmail: ");
						strBuff.append(fpUser.getEmailAddress());
						strBuff.append("\n\t\t\tContact Phone Number: ");
						strBuff.append(fpUser.getContactPhoneNumber());		
					}
				}
			} else { // position without time slots	
				for (Object fp: resultList) {
					FilledVolunteerRequisition filledReq = getJpaTemplate().find(FilledVolunteerRequisition.class, 
							((FilledVolunteerRequisition)fp).getId());
					User fpUser = getJpaTemplate().find(User.class, filledReq.getUser().getId());
					strBuff.append("\n\t");
					strBuff.append(fpUser.getFirstName());
					strBuff.append(" ");
					strBuff.append(fpUser.getLastName());
					strBuff.append("\n\t\tEmail: ");
					strBuff.append(fpUser.getEmailAddress());
					strBuff.append("\n\t\tContact Phone Number: ");
					strBuff.append(fpUser.getContactPhoneNumber());					
				}
			}
		}
		return strBuff.toString();
	}

	@Override
	public FilledVolunteerRequisition registerForEventByPosition(Position p,
			User user) {
		Position storedPosition = getJpaTemplate().find(Position.class, p.getId());
		Event storedEvent = getJpaTemplate().find(Event.class, storedPosition.getEvent().getId());
		User storedUser = getJpaTemplate().find(User.class, user.getId());
		FilledVolunteerRequisition fvr = new FilledVolunteerRequisition(storedUser, storedEvent, storedPosition);
		getJpaTemplate().persist(fvr);
		return fvr;
	}

	@Override
	public FilledVolunteerRequisition registerForEventByTimeSlot(TimeSlot ts,
			User user) {
		TimeSlot storedTimeSlot = getJpaTemplate().find(TimeSlot.class, ts.getId());
		Position storedPosition = getJpaTemplate().find(Position.class, storedTimeSlot.getPosition().getId());
		Event storedEvent = getJpaTemplate().find(Event.class, storedPosition.getEvent().getId());
		User storedUser = getJpaTemplate().find(User.class, user.getId());
		FilledVolunteerRequisition fvr = new FilledVolunteerRequisition(storedUser, storedEvent, storedPosition, storedTimeSlot);
		getJpaTemplate().persist(fvr);
		return fvr;
	}

	@Override
	public void unregisterForEventByPosition(Position p, User user) {
		Position storedPosition = getJpaTemplate().find(Position.class, p.getId());
		Event storedEvent = getJpaTemplate().find(Event.class, storedPosition.getEvent().getId());
		User storedUser = getJpaTemplate().find(User.class, user.getId());
		
		List resultList = getJpaTemplate().find("select f from  FilledVolunteerRequisition f where f.event = ?1 AND f.position = ?2 AND f.user = ?3",
				storedEvent, storedPosition, storedUser);
		
		if (!resultList.isEmpty()) {
			FilledVolunteerRequisition fvr = (FilledVolunteerRequisition) resultList.get(0);
			getJpaTemplate().remove(fvr);
		}
		
		
	}

	@Override
	public void unregisterForEventByTimeSlot(TimeSlot ts, User user) {
		TimeSlot storedTimeSlot = getJpaTemplate().find(TimeSlot.class, ts.getId());
		Position storedPosition = getJpaTemplate().find(Position.class, storedTimeSlot.getPosition().getId());
		Event storedEvent = getJpaTemplate().find(Event.class, storedPosition.getEvent().getId());
		User storedUser = getJpaTemplate().find(User.class, user.getId());

		List resultList = getJpaTemplate().find("select f from  FilledVolunteerRequisition f where f.event = ?1 AND f.position = ?2 AND f.timeSlot = ?3 AND f.user = ?4",
				storedEvent, storedPosition, storedTimeSlot, storedUser);
		if (!resultList.isEmpty()) {
			FilledVolunteerRequisition fvr = (FilledVolunteerRequisition) resultList.get(0);
			getJpaTemplate().remove(fvr);
		}
	}

}
